package com.zh.freechat.domain.user.service;

import com.zh.freechat.common.req.EditGroupForm;
import com.zh.freechat.common.req.GroupForm;
import com.zh.freechat.common.resp.ChatRelationDTO;
import com.zh.freechat.domain.message.entity.ChatGroupPO;
import com.zh.freechat.domain.message.entity.ChatMsgPO;
import com.zh.freechat.domain.message.entity.ChatRelationPO;
import com.zh.freechat.domain.message.entity.GroupMemberPO;
import com.zh.freechat.domain.message.repository.ChatGroupRepository;
import com.zh.freechat.domain.message.repository.ChatMsgPoRepository;
import com.zh.freechat.domain.message.repository.real.ChatRelationPoMapper;
import com.zh.freechat.domain.user.entity.ChatUser;
import com.zh.freechat.domain.user.entity.UserContacts;
import com.zh.freechat.domain.user.repository.UserContactRepository;
import com.zh.freechat.domain.user.repository.UserRepository;
import com.zh.mycommon.util.RandomCodeUtil;
import io.jsonwebtoken.lang.Assert;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.zh.mycommon.viewdata.ToWrapper.foreach;
import static com.zh.mycommon.viewdata.ToWrapper.setString;

/**
 * 用户聊天service
 *
 * @author ZH
 * @date 10:47 2021/7/16
 */
@Slf4j
@AllArgsConstructor
@Service
public class UserChatService {
    private final UserRepository userRepository;
    private final ChatMsgPoRepository chatMsgPoRepository;
    private final ChatGroupRepository chatGroupRepository;
    private final UserContactRepository userContactRepository;
    private final ChatRelationPoMapper chatRelationPoMapper;

    /**
     * 获取在线的好友IDs
     *
     * @param userId 此用户的userId
     * @return 处于在线状态的好友ID list
     */
    public List<String> onlineUsers(String userId) {
        UserContacts contacts = userContactRepository.findContacts(userId);
        return contacts.getFriends().stream()
                .map(e -> e.getFriendId(userId))
                .distinct()
                .collect(Collectors.toList());
    }

    /**
     * 获取用户的聊天关系列表
     *
     * @param userId 用户ID
     * @return 聊天列表
     */
    public List<ChatRelationDTO> findChatRelations(String userId) {
        //查询数据
        List<ChatRelationPO> chatRelationPOS = chatRelationPoMapper.findAllByUser(userId);

        var chatuserIds = chatRelationPOS.stream().map(e -> {
            return userId.equals(e.getUser1()) ? e.getUser2() : e.getUser1();
        }).collect(Collectors.toSet());

        //缓存的ChatUser Map数据
        Map<String, ChatUser> chatUsersMap = userRepository.selectByIds(new ArrayList<>(chatuserIds)).stream()
                .collect(Collectors.toMap(ChatUser::getUid, Function.identity()));

        //暂存返回结果
        return chatRelationPOS.stream()
                .map(e -> buildChatterRelationDTO(e, userId, chatUsersMap))
                .collect(Collectors.toList());
    }

    @NotNull
    private ChatRelationDTO buildChatterRelationDTO(ChatRelationPO relationPO, String userId, Map<String, ChatUser> chatUsersMap) {
        String chatterId = userId.equals(relationPO.getUser1()) ? relationPO.getUser2() : relationPO.getUser1();
        var chatterRelationDTO = new ChatRelationDTO(relationPO.getId(), userId, chatUsersMap.get(chatterId));
        chatterRelationDTO.setLastTime(relationPO.getLastTime());

        //如果允许陌生人聊天，则获取聊天关系陌生人
        boolean friend = userContactRepository.isFriendRelation(userId, chatterId);
        chatterRelationDTO.setIsFriend(friend); //标记是不是朋友
        return chatterRelationDTO;
    }

    /**
     * 获取聊天消息流
     * 顺序是由近到远
     *
     * @param chatId 聊天关系ID
     * @param isGroup 是不是群聊消息
     * @param msgId  消息ID，根据此消息的createTime为基准去查询之前的消息
     * @param size 限制查询消息的条数
     * @return list
     */
    public List<ChatMsgPO> findChatMsgs(String chatId, boolean isGroup, long msgId, int size) {
//        beforeTime = beforeTime > 0 ? beforeTime : System.currentTimeMillis();
//        var days = 30;
        //查询时间范围
//        var startTime = LocalDateTime.of(LocalDate.now().minusDays(days), LocalTime.MIN);
//        var endTime = MyDateUtil.convertToLocalDateTime(beforeTime);

        return chatMsgPoRepository.findChatMsgByUserId(chatId, isGroup, msgId, size);
    }

    /**
     * 创建聊天群
     *
     * @param form data
     * @return groupNO
     */
    public String createGroup(@NotNull GroupForm form) {
        ChatGroupPO groupRelPO = new ChatGroupPO();
        groupRelPO.setGroupNo(nexGroupNo());
        groupRelPO.setName(form.getName());
        groupRelPO.setOwnerUid(form.getOwnerUid());
        groupRelPO.setAvatar(form.getAvatar());
        groupRelPO.setUsers(new ArrayList<>());

        if (form.getUsers() != null) {
            var userIds = foreach(form.getUsers(), GroupForm.MemberItem::getUserId);
            //缓存的ChatUser Map数据
            Map<String, ChatUser> chatUsersMap = userRepository.selectByIds(userIds).stream()
                    .collect(Collectors.toMap(ChatUser::getUid, Function.identity()));

            groupRelPO.getUsers().addAll(foreach(form.getUsers(), (e) -> buildGroupMember(e, chatUsersMap.get(e.getUserId()))));
        }

        chatGroupRepository.save(groupRelPO);
        return groupRelPO.getGroupNo();
    }

    private String nexGroupNo() {
        while (true) {
            var randCode = RandomCodeUtil.getNumberCode(10);
            if (!chatGroupRepository.existByGroupNo(randCode)) {
                return randCode;
            }
        }
    }

    @Transactional
    public void deleteGroup(@NotNull String groupNo) {
        chatGroupRepository.deleteByGroupNo(groupNo);
    }

    @Transactional
    public void groupAddMembers(List<GroupForm.MemberItem> items) {
        if (CollectionUtils.isEmpty(items)) return;

        Assert.hasText(items.getFirst().getGroupNo(), "缺少groupNo参数值");

        var userIds = foreach(items, GroupForm.MemberItem::getUserId);
        //缓存的ChatUser Map数据
        Map<String, ChatUser> chatUsersMap = userRepository.selectByIds(userIds).stream()
                .collect(Collectors.toMap(ChatUser::getUid, Function.identity()));

        var groupNo = items.getFirst().getGroupNo();


        foreach(items, e -> buildGroupMember(e, chatUsersMap.get(e.getUserId())))
                .forEach(member -> {
                    try {
                        chatGroupRepository.addMember(member, groupNo);
                    } catch (Exception e) {
                        log.warn("addMember 未成功。 cause: {}", e.getMessage());
                    }
                });
    }

    public void groupDropMember(@NotNull GroupForm.MemberItem item) {
        chatGroupRepository.removeMember(item.getUserId(), item.getGroupNo());
    }

    public ChatGroupPO findGroupById(@NotNull Long relId) {
        return chatGroupRepository.findByGroupId(relId);
    }

    public ChatGroupPO findGroupByNo(@NotNull String groupNo) {
        return chatGroupRepository.findByGroupNo(groupNo);
    }

    public List<ChatGroupPO> findGroupsByUser(@NotNull String userId) {
        return chatGroupRepository.findGroupsByMember(userId);
    }

    @NotNull
    private static GroupMemberPO buildGroupMember(@NotNull GroupForm.MemberItem e, @Nullable ChatUser user) {
        if (user == null) return new GroupMemberPO();

        GroupMemberPO memberPO = new GroupMemberPO();
        memberPO.setAliasName(e.getAliasName());
        memberPO.setNickname(user.getNickname());
        memberPO.setUserId(user.getUid());
        memberPO.setAvatarUrl(user.getAvatarUrl());
        memberPO.setGender(user.getGender());
        return memberPO;
    }

    public void editGroup(EditGroupForm form, @NotNull Long groupId) {
        ChatGroupPO chatGroupPO = new ChatGroupPO();
        chatGroupPO.setId(groupId);

        setString(chatGroupPO::setName).accept(form.getName());
        setString(chatGroupPO::setAvatar).accept(form.getAvatar());
        setString(chatGroupPO::setOwnerUid).accept(form.getOwnerUid());

        chatGroupRepository.update(chatGroupPO);
    }

}
